//
//  RulerView.swift
//  AmountBody
//
//  Created by Qiu Jishuai on 2018/1/26.
//  Copyright © 2018年 RCMTM. All rights reserved.
//

import UIKit

@objcMembers
class RulerView: UIView, UIScrollViewDelegate {

    //    var decorate  装饰性的绘制
    typealias SelectedCompletion = (_ index: Int, _ selectedItem: String) -> Void

    var selectedCompletion: SelectedCompletion?

    var items: [String] = []

    var currentIndex: Int? {
        didSet {
            guard let index = currentIndex else { return }
            setCurrentIndex(index, animated: false)
        }
    }

    func setCurrentIndex(_ index: Int, animated: Bool) {
        var target = index
        lastIndex = target
        if isDrawed {
            if target < 0 {
                target = 0
            }
            if target > items.count - 1 {
                target = items.count - 1
            }
            let x = CGFloat(target * unitWidth * scrollableUnitCount)
            scrollView.setContentOffset(CGPoint(x: x, y: 0), animated: animated)
        }
    }

    //滑动减速速率  默认0.3
    var decelerationRate: CGFloat = 0.3 {
        didSet {
            scrollView.decelerationRate = decelerationRate
        }
    }

    lazy var scrollView: UIScrollView = {
        let scrollView = UIScrollView()
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.showsVerticalScrollIndicator = false
        scrollView.decelerationRate = self.decelerationRate
        scrollView.delegate = self
        return scrollView
    }()

    let pointer: UIImageView = {
        let imageView = UIImageView()
        imageView.clipsToBounds = true
        imageView.image = #imageLiteral(resourceName: "Triangle")
        imageView.contentMode = .scaleAspectFit
        return imageView
    }()

    let backgroundImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFill
        return imageView
    }()

    //指针偏移 默认zero
    var pointerOffSet: CGPoint = CGPoint(x: 0, y: -22) {
        didSet {
            updatePointerConstrains()
            //            redrawPath()
        }
    }

    /// 指针尺寸 默认 30 10
    var pointerSize: CGSize = CGSize(width: 10, height: 10) {
        didSet {
            updatePointerConstrains()
        }
    }

    private let rulerContainerView = UIView()

    private let lineLayer = CAShapeLayer()

    private func updatePointerConstrains() {
        if pointer.constraints.count > 0 {
            pointer.removeConstraints(pointer.constraints)
        }
        pointer.translatesAutoresizingMaskIntoConstraints = false
        let centerX = NSLayoutConstraint(item: pointer, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: pointerOffSet.x)
        let bottom = NSLayoutConstraint(item: pointer, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: pointerOffSet.y)

        let width = NSLayoutConstraint(item: pointer, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: pointerSize.width)

        let height = NSLayoutConstraint(item: pointer, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: pointerSize.height)

        addConstraints([centerX, bottom, width, height])
        layoutIfNeeded()
    }

    /// 可滚动的最小跨度 默认为10个按最小单元格  设置的数字应为10的倍数
    var scrollableUnitCount: Int = 10 {
        didSet {
            assert(scrollableUnitCount % 10 == 0, "texts类型的设置的数字应为10的倍数, 当前为\(scrollableUnitCount)")
        }
    }

    /// 每个单元格的宽度, 默认5pt 不能小于1pt
    var unitWidth: Int = 5 {
        didSet {
            assert(unitWidth >= 1, "单元格宽度需要大于1, 当前为\(unitWidth)")
        }
    }

    /// 刻度值字体
    var scaleIntervalFont: UIFont = .systemFont(ofSize: 12)

    /// 高亮显示字体的比例
    var highlightedScale: CGFloat = 1.2
    /// 短刻度值线宽
    var shortLineWidth: CGFloat = 1 / UIScreen.main.scale
    /// 长刻度值线宽
    var longLineWidth: CGFloat = 1.0
    /// 中刻度值线宽
    var mediumLineWidth: CGFloat = 1.0
    /// 水平线宽
    var horizontalLineWidth: CGFloat = 1.0
    /// 长刻度值 长度占总体的比例
    var longLineHeightScale: CGFloat = 0.5
    /// 中刻度值 长度占总体的比例
    var mediumLineHeightScale: CGFloat = 0.375
    /// 短刻度值 长度占总体的比例
    var shortLineHeightScale: CGFloat = 0.25

    /// 文字的颜色
    var textColor: UIColor = .black {
        didSet {
            redrawTexts()
        }
    }

    /// 线的颜色
    var lineColor: UIColor = .black {
        didSet {
            lineLayer.fillColor = lineColor.cgColor
        }
    }

    //显示的文字  默认为全部显示 具体可由子类重载
    //    var textFor: String {

    //    }

    private var textLayers: [CATextLayer] = []

    override init(frame: CGRect) {
        super.init(frame: frame)

        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        setup()
    }

    private func setup() {

        addSubview(scrollView)
        addSubview(pointer)
        scrollView.addSubview(rulerContainerView)
        rulerContainerView.layer.addSublayer(lineLayer)

        updatePointerConstrains()

        scrollView.translatesAutoresizingMaskIntoConstraints = false
        let top = NSLayoutConstraint(item: scrollView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0)
        let left = NSLayoutConstraint(item: scrollView, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1, constant: 0)
        let bottom = NSLayoutConstraint(item: scrollView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)
        let right = NSLayoutConstraint(item: scrollView, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1, constant: 0)

        addConstraints([top, left, bottom, right])

        redrawPath()
    }

    private var lineLayerHeight: CGFloat {
        return frame.height * 0.625
    }

    private var contentWidth: CGFloat {
        return CGFloat(unitWidth * scrollableUnitCount * (items.count - 1))
    }


    private var isDrawed = false
    override func layoutSubviews() {
        super.layoutSubviews()

        let height = bounds.height

        if rulerContainerView.frame.height != height {
            isDrawed = true
            let width = bounds.width
            rulerContainerView.frame = CGRect(x: width / 2, y: 0, width: contentWidth, height: height)
            scrollView.contentSize = CGSize(width: contentWidth + width, height: 0)
            let x = CGFloat(lastIndex) / CGFloat(items.count - 1) * contentWidth
            scrollView.contentOffset = CGPoint(x: x, y: 0)
            lineLayer.frame = CGRect(x: 0, y: height - lineLayerHeight, width:  contentWidth, height: lineLayerHeight)
            redrawPath()
            redrawTexts()
            guard lastIndex < items.count - 1 else { return }
            selectedCompletion?(lastIndex, items[lastIndex])
        }
    }

    private func redrawPath() {
        let lineLayerHeight = self.lineLayerHeight
        let height = rulerContainerView.frame.height
        let width = rulerContainerView.frame.width

        if lineLayerHeight == 0 || width == 0 || height == 0{
            lineLayer.path = nil
            return
        }

        //绘制横线
        let horizontalFrame = CGRect(x: 0, y: lineLayerHeight - horizontalLineWidth, width: width, height: horizontalLineWidth)
        let path = UIBezierPath(rect: horizontalFrame)

        //绘制
        for i in 0...((items.count - 1) * scrollableUnitCount) {
            let lineHeight: CGFloat
            let lineWidth: CGFloat
            if i % 10 == 0 {
                lineHeight = longLineHeightScale * height
                lineWidth = longLineWidth
            } else if i % 5 == 0 {
                lineHeight = mediumLineHeightScale * height
                lineWidth = mediumLineWidth
            } else {
                lineHeight = shortLineHeightScale * height
                lineWidth = shortLineWidth
            }
            if lineHeight == 0 || lineWidth == 0 {
                continue
            }
            let y = lineLayerHeight - lineHeight - horizontalLineWidth

            let x = CGFloat(i * unitWidth) - lineWidth / 2
            let rect = CGRect(x: x, y: y, width: lineWidth, height: lineHeight)
            let verticalLine = UIBezierPath(rect: rect)
            path.append(verticalLine)
            //            print("verticalLine", x, width)
        }

        lineLayer.path = path.cgPath
    }

    private func redrawTexts() {

        let texts = items.map{ "\($0)" }
        //绘制刻度值
        let attributes: [NSAttributedStringKey: Any] = [.foregroundColor: textColor,
                                                        .font: scaleIntervalFont]

        while textLayers.count > texts.count {
            let last = textLayers.removeLast()
            last.removeFromSuperlayer()
        }

        while textLayers.count < texts.count {
            let textLayer = CATextLayer()
//            textLayer.shouldRasterize = true
//            textLayer.contentsScale = UIScreen.main.scale
            textLayer.alignmentMode = kCAAlignmentCenter
            rulerContainerView.layer.addSublayer(textLayer)
            textLayers.append(textLayer)
        }

        let itemWidth = contentWidth / CGFloat(items.count - 1) //等于一个单元格的宽度
        let height = rulerContainerView.frame.height * 0.4
        for (index, textLayer) in textLayers.enumerated() {
            textLayer.string = NSAttributedString(string: texts[index], attributes: attributes)
            textLayer.frame = CGRect(x: itemWidth * CGFloat(index) - itemWidth / 2, y: 5, width: itemWidth, height: height)
        }
    }

    //指针对应标尺中的位置
    private var poineterOriginInRuler: CGPoint {
        return convert(pointer.center, to: rulerContainerView)
    }

    //纠正偏移量后的点
    private func adjustedPoint(with point: CGPoint) -> CGPoint {
        let x = round(point.x)
        let scrollableWidth = unitWidth * scrollableUnitCount

        var deviation = CGFloat(Int(x) % (scrollableWidth))

        if deviation < CGFloat(scrollableWidth) / 2 {
            deviation = -deviation
        } else {
            deviation = CGFloat(scrollableWidth) - deviation
        }
        return CGPoint(x: x + deviation, y: point.y)
    }

    private var lastIndex: Int = 0

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offsetX = scrollView.contentOffset.x

        let itemWidth = unitWidth * scrollableUnitCount
        let currentIndex = (Int(offsetX) + itemWidth / 2) / itemWidth
        if currentIndex == lastIndex || currentIndex > items.count - 1 {
            return
        }
        let currentItem = items[currentIndex]
        lastIndex = currentIndex
        selectedCompletion?(currentIndex, currentItem)
    }

    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        targetContentOffset.pointee = adjustedPoint(with: targetContentOffset.pointee)
    }
}
